package com.saas.ability.core.base.http;

import com.alibaba.fastjson.JSON;
import com.saas.ability.core.base.security.Base64Util;
import com.saas.ability.core.base.util.UploadUtil;
import com.google.common.io.ByteStreams;
import org.apache.http.HttpResponse;
import org.apache.http.StatusLine;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Map;

public class RpcClient {
	
	@Autowired
	UploadUtil uploadUtil;
	
	static Logger logger  = LoggerFactory.getLogger(HttpConnectionManager.class);
	
	private static int maxRetryNumber = 3;
	
    private static boolean autoRetry = true;
    
	HttpConnectionManager connManager;
	
	public RpcClient() {
		this.connManager = new HttpConnectionManager();
		this.connManager.init();
	}
	
	public <T> T post(String url,Map<String,Object> params,Class<T> clazz){
		HttpPost httpPost = PostEndpoint.getHttpPost(url, params);
		Resp resp = execute(httpPost);
		int retryTime = 1;
		if(autoRetry && retryTime < maxRetryNumber 
				&& resp.getRetCode() != Resp.SUCC){
			resp = execute(httpPost);
			retryTime++;
		}
		if(resp.getRetCode() == Resp.SUCC){
			return JSON.parseObject(resp.getRetData(), clazz);
		}else{
			logger.error("RPC请求处理不成功,retCode:{},retData:{},statusCode:{}", 
					resp.getRetCode(),resp.getRetData(),resp.getStatusCode());
			throw new RuntimeException("rpc请求处理不成功");
		}
    }
	
	public String post(String url,Map<String,Object> params){
		HttpPost httpPost = PostEndpoint.getHttpPost(url, params);
		Resp resp = execute(httpPost);
		int retryTime = 1;
		if(autoRetry && retryTime < maxRetryNumber 
				&& resp.getRetCode() != Resp.SUCC){
			resp = execute(httpPost);
			retryTime++;
		}
		if(resp.getRetCode() == Resp.SUCC){
			return resp.getRetData();
		}else{
			logger.error("RPC请求处理不成功,retCode:{},retData:{},statusCode:{}",
					resp.getRetCode(),resp.getRetData(),resp.getStatusCode());
			throw new RuntimeException("rpc请求处理不成功");
		}
    }
	
	public String postJSON(String url,Map<String,Object> params,String fileName){
		HttpPost httpPost = PostEndpoint.getHttpPostJSON(url, params);
        Resp resp = executeStr(httpPost, fileName);
        int retryTime = 1;
        if (autoRetry && retryTime < maxRetryNumber
                && resp.getRetCode() != Resp.SUCC){
            resp = executeStr(httpPost, fileName);
            retryTime++;
		}
		if(resp.getRetCode() == Resp.SUCC){
			return resp.getRetData();
		}else{
            logger.error("RPC请求处理不成功,retCode:{},retData:{},statusCode:{}",
                    resp.getRetCode(),resp.getRetData(),resp.getStatusCode());
			throw new RuntimeException("rpc请求处理不成功");
		}
    }

	public String postJSONNoUpload(String url,Map<String,Object> params,String fileName){
		HttpPost httpPost = PostEndpoint.getHttpPostJSON(url, params);
		Resp resp = executeStrNoUpload(httpPost, fileName);
		int retryTime = 1;
		if (autoRetry && retryTime < maxRetryNumber
				&& resp.getRetCode() != Resp.SUCC){
			resp = executeStrNoUpload(httpPost, fileName);
			retryTime++;
		}
		if(resp.getRetCode() == Resp.SUCC){
			return resp.getRetData();
		}else{
			logger.error("RPC请求处理不成功,retCode:{},retData:{},statusCode:{}",
					resp.getRetCode(),resp.getRetData(),resp.getStatusCode());
			throw new RuntimeException("rpc请求处理不成功");
		}
	}

	public String postWxJSON(String url, String jsonStr){
		/*HttpPost httpPost = PostEndpoint.getHttpPostJSON(url, jsonObject);
		Resp resp = execute(httpPost);
		int retryTime = 1;
		if(autoRetry && retryTime < maxRetryNumber
				&& resp.getRetCode() != Resp.SUCC){
			resp = execute(httpPost);
			retryTime++;
		}
		if(resp.getRetCode() == Resp.SUCC){
			return resp.getRetData();
		}else{
			logger.error("RPC请求处理不成功,retCode:{},retData:{},statusCode:{}",
					resp.getRetCode(),resp.getRetData(),resp.getStatusCode());
			throw new RuntimeException("rpc请求处理不成功");
		}*/
		// 创建Httpclient对象
		CloseableHttpClient httpClient = HttpClients.createDefault();
		CloseableHttpResponse response = null;
		String resultString = "";
		try {
			// 创建Http Post请求
			HttpPost httpPost = new HttpPost(url);
			// 创建请求内容
			StringEntity entity = new StringEntity(jsonStr, ContentType.APPLICATION_JSON);
			httpPost.setEntity(entity);
			// 执行http请求
			response = httpClient.execute(httpPost);
			resultString = EntityUtils.toString(response.getEntity(), "utf-8");
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				response.close();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

		return resultString;
	}
	
	public <T> T get(String url,Class<T> clazz){
		return get(url,null,clazz);
	}
	
	public <T> T get(String url,Map<String,String> params,Class<T> clazz){
		HttpGet httpget = GetEndpoint.getHttpGet(url, params);
		Resp resp = execute(httpget);
		int retryTime = 1;
		if(autoRetry && retryTime < maxRetryNumber 
				&& resp.getRetCode() != Resp.SUCC){
			resp = execute(httpget);
			retryTime++;
		}
		if(resp.getRetCode() == Resp.SUCC){
			return JSON.parseObject(resp.getRetData(), clazz);
		}else{
			logger.error("RPC请求处理不成功,retCode:{},retData:{},statusCode:{}", 
					resp.getRetCode(),resp.getRetData(),resp.getStatusCode());
			throw new RuntimeException("rpc请求处理不成功");
		}
    }
	
	public Resp execute(HttpRequestBase httpReq){
		CloseableHttpResponse response;
		Resp resp = new Resp();
		try {
			CloseableHttpClient httpClient = connManager.getHttpClient();
			response = httpClient.execute(httpReq);
			StatusLine statusLine = response.getStatusLine();
			String result = EntityUtils.toString(response.getEntity());
			if(statusLine.getStatusCode() == 200){
	    		resp.setStatusCode(statusLine.getStatusCode());
	    		resp.setRetData(result);
	        }else{
	        	resp.setRetCode(Resp.FAIL);
	        	resp.setStatusCode(statusLine.getStatusCode());
	        	resp.setRetData(statusLine.getReasonPhrase());
	        }
		} catch (ClientProtocolException e) {
			resp.setRetCode(Resp.FAIL);
        	resp.setRetData(e.getMessage());
		} catch (IOException e) {
			resp.setRetCode(Resp.FAIL);
        	resp.setRetData(e.getMessage());
		}
    	return resp;
	}
	
	public Resp executeStr(HttpRequestBase httpReq,String filePathName){
		CloseableHttpResponse response;
		Resp resp = new Resp();
		try {
			CloseableHttpClient httpClient = connManager.getHttpClient();
			response = httpClient.execute(httpReq);
			StatusLine statusLine = response.getStatusLine();
			if(statusLine.getStatusCode() == 200){
				byte[] bt = EntityUtils.toByteArray(response.getEntity());
                if (new String(bt).contains("errcode")) {
                    resp.setRetCode(Resp.FAIL);
                    resp.setStatusCode(statusLine.getStatusCode());
                    resp.setRetData(new String(bt));
                    return resp;
                }
                InputStream input = new ByteArrayInputStream(bt);
				//将小程序码上传到oss
				String path = uploadUtil.putObjectReturnUrl(filePathName, input);
                resp.setRetData(path);
            }else{
	        	resp.setRetCode(Resp.FAIL);
	        	resp.setStatusCode(statusLine.getStatusCode());
	        	resp.setRetData(statusLine.getReasonPhrase());
	        }
		} catch (ClientProtocolException e) {
			resp.setRetCode(Resp.FAIL);
        	resp.setRetData(e.getMessage());
		} catch (IOException e) {
			resp.setRetCode(Resp.FAIL);
        	resp.setRetData(e.getMessage());
		}
    	return resp;
	}

	public Resp executeStrNoUpload(HttpRequestBase httpReq,String filePathName){
		CloseableHttpResponse response;
		Resp resp = new Resp();
		try {
			CloseableHttpClient httpClient = connManager.getHttpClient();
			response = httpClient.execute(httpReq);
			StatusLine statusLine = response.getStatusLine();
			if(statusLine.getStatusCode() == 200){
				byte[] bt = EntityUtils.toByteArray(response.getEntity());
				if (new String(bt).contains("errcode")) {
					resp.setStatusCode(statusLine.getStatusCode());
					resp.setRetCode(Resp.FAIL);
					resp.setRetData(new String(bt));
					return resp;
				}
				InputStream input = new ByteArrayInputStream(bt);
				//将流转化为base64传递给前端
				byte[] bytes = ByteStreams.toByteArray(input);
				String base64 = Base64Util.encodeBase64(bytes);
				resp.setRetData(base64);
			}else{
				resp.setRetCode(Resp.FAIL);
				resp.setStatusCode(statusLine.getStatusCode());
				resp.setRetData(statusLine.getReasonPhrase());
			}
		} catch (ClientProtocolException e) {
			resp.setRetCode(Resp.FAIL);
			resp.setRetData(e.getMessage());
		} catch (IOException e) {
			resp.setRetCode(Resp.FAIL);
			resp.setRetData(e.getMessage());
		}
		return resp;
	}

	/**
	 * POST  上传文件
	 * @param fileName
	 * 上传的文件
	 * @return 响应结果
	 */
	public String httpClientUploadFile(String url,InputStream is,String fileName) throws IOException {
		String result = null;
		BufferedReader reader = null;
		/**
		 * 第一部分
		 */
		try {
			URL urlObj = new URL(url);
			HttpURLConnection con = (HttpURLConnection) urlObj.openConnection();
			con.setRequestMethod("POST"); // 以Post方式提交表单，默认get方式
			con.setDoInput(true);
			con.setDoOutput(true);
			con.setUseCaches(false); // post方式不能使用缓存
			// 设置请求头信息
			con.setRequestProperty("Connection", "Keep-Alive");
			con.setRequestProperty("Charset", "UTF-8");
			// 设置边界
			String BOUNDARY = "----------" + System.currentTimeMillis();
			con.setRequestProperty("Content-Type", "multipart/form-data; boundary="+ BOUNDARY);
			// 请求正文信息
			// 第一部分：
			StringBuilder sb = new StringBuilder();
			sb.append("--"); // 必须多两道线
			sb.append(BOUNDARY);
			sb.append("\r\n");
			sb.append("Content-Disposition: form-data;name=\"file\";filename=\""+ fileName + "\"\r\n");
			sb.append("Content-Type:application/octet-stream\r\n\r\n");
			byte[] head = sb.toString().getBytes("utf-8");
			// 获得输出流
			OutputStream out = new DataOutputStream(con.getOutputStream());
			// 输出表头
			out.write(head);
			// 文件正文部分
			// 把文件已流文件的方式 推入到url中
			DataInputStream in = new DataInputStream(is);
			int bytes = 0;
			byte[] bufferOut = new byte[1024];
			while ((bytes = in.read(bufferOut)) != -1) {
				out.write(bufferOut, 0, bytes);
			}
			in.close();
			// 结尾部分
			byte[] foot = ("\r\n--" + BOUNDARY + "--\r\n").getBytes("utf-8");// 定义最后数据分隔线
			out.write(foot);
			out.flush();
			out.close();
			StringBuffer buffer = new StringBuffer();

			// 定义BufferedReader输入流来读取URL的响应
			reader = new BufferedReader(new InputStreamReader(con.getInputStream()));
			String line = null;
			while ((line = reader.readLine()) != null) {
				//System.out.println(line);
				buffer.append(line);
			}
			if(result==null){
				result = buffer.toString();
			}
		} catch (IOException e) {
			System.out.println("发送POST请求出现异常！" + e);
			e.printStackTrace();
		} finally {
			if(reader!=null){
				reader.close();
			}
		}
		return result;
	}

	/**
	 * 读取网络图片
	 * @param url
	 * @return
	 */
	public String readNetWorkPic(String url){
		String result = "";
		//创建客户端，实例化HttpClient对象
		HttpClient client = new DefaultHttpClient();
		//创建get请求，实例化HttpGet对象，需要指定资源地址
		HttpGet httpGet = new HttpGet(url);// ******地址
		try{
			HttpResponse res = client.execute(httpGet);
			//根据返回的状态码，判断是否成功（200），进行读写操作
			if (res.getStatusLine().getStatusCode() == 200) {
				byte[] b = EntityUtils.toByteArray(res.getEntity());
				result = Base64Util.encodeBase64(b);
			}
		}catch (Exception e){
			e.printStackTrace();
		}
		return result;
	}
}
